/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-12-20
 * Time: 04:10
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;

namespace patterns
{
	/// <summary>
	/// The subject for observation. All instances of Observer declaring the same base 
	/// state class as template argument as this instance can observe this instance.
	/// 
	/// Implements the Observer design pattern
	/// </summary>
	public abstract class SubjectForObservation<StateType>
	{
		#region members
		
		/// <summary>
		/// Reference to the current state of this subject,
		/// private, so it can only be modified by the method SetSubjectsState
		/// </summary>
		private StateType						m_State;
		/// <summary>
		/// References to all the currently registered observers
		/// </summary>
		private List<Observer<StateType>>		m_Observers;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		protected SubjectForObservation()
		{
			m_State = default(StateType);
			m_Observers = new List<Observer<StateType>>();
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Sets the state of the subject, and calls update on all observers
		/// </summary>
		/// <param name="state">The state to set</param>
		public void SetSubjectsState(StateType state)
		{
			m_State = state;
			UpdateObservers();
		}
		
		#endregion
		
		#region internal methods
		
		/// <summary>
		/// Registers a new observer, can only be called from inside this assembly
		/// Only adds the observer if this observer is not allready registered with
		/// this subject
		/// </summary>
		/// <param name="observer">The observer to add</param>
		internal void AddObserver(Observer<StateType> observer)
		{
			if(!m_Observers.Contains(observer))
			{
				m_Observers.Add(observer);
			}
		}
		
		/// <summary>
		/// Removes an observer, can only be called from inside this assembly
		/// If the observer is not registered with this subject, nothing happens
		/// </summary>
		/// <param name="observer">The observer to remove</param>
		internal void RemoveObserver(Observer<StateType> observer)
		{
			if(m_Observers.Contains(observer))
			{
				m_Observers.Remove(observer);
			}
		}
		
		#endregion
		
		#region protected methods
		
		/// <summary>
		/// Calls update on all observers
		/// </summary>
		protected void UpdateObservers()
		{
			foreach(Observer<StateType> it in m_Observers)
			{
				it.UpdateObserver();
			}
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// Reference to the current state (get)
		/// </summary>
		protected internal StateType State
		{
			get
			{
				return m_State;
			}
		}
		
		#endregion
	}
}
